#include <iostream>
#include <string>
using namespace std;
#include "../client/bufferDB.h"
#include "bufDBServer.h"
#include "../setup/connect.h"
#include <libpq-fe.h>
#include <libpq/libpq-fs.h>

bufDBServer::bufDBServer(int argc, char* argv[])
{
	con = connect(argc, argv);
	colName.str( "" );
	values.str("");
	string results("");		
}

////////////////////////////////////////////////////////////////////////////////
// SaveToDatabase()
//
// Description: This function will walk the data stream input from the client-server
// 		socket interface and start the string stream to create the SQL command. 
//		Then, it will call the getDataTypeAndStore function to complete the string
//		stream, complete the SQL command and call the addStringDataToTable function.
// Inputs: db::Database *msg
// 
//
// Outputs: none
//
// Return: none
/////////////////////////////////////////////////////////////////////////////////
void bufDBServer::SaveToDatabase(db::Database *msg)
{	
	//First Determine how many messages are in the file
	//The deque inData contains the data read from the file.
	//The array msgSize contains the size of each of the messages
	//ie: The number of tokens in each
	//int totalInputMsgs = sever.messagesInFile(filename, msgSize);
	setNewMessage(msg);	
	int totalProtoMsgs = bufDBServer::findRepeatedFields();//default value is 2
	
	int totalNestedTypes = bufDBServer::findNestedTypes();//default is 2 tell us where the player or team is 
	
	
	/**/
					
	//Iterate through each message and store the fields
	for(int msgCnt = 0; msgCnt < totalProtoMsgs; msgCnt++)
	{

		//Set your indexes to point to the correct field
		//Repeated field gives you the data
		//Nested field gives you the type of data
		bufDBServer::setRepeatedMsgPtr(msgCnt);
		bufDBServer::setNestedTypePtr(msgCnt);
		
		//Once you are pointing at the correct Nested Type
		//you must determine the type of each token in the Nested Type
		//This is equivalent the type of each comma seperated value
		//on a line of the input file.
		int totalNestedTokenTypes = bufDBServer::findNestedTokenTypes();	//default value should be 2	
			
		for(int entryCnt = 0; entryCnt<bufDBServer::getEntryCnt(); entryCnt++)
		{
			bufDBServer::setMessageEntryPtr(entryCnt);
			
			colName.str("");
			values.str("");
			colName<<"(";
			values<<"(";
			
			for(int tokenTypeCnt=0; tokenTypeCnt<totalNestedTokenTypes;tokenTypeCnt++)
			{
			
				bufDBServer::setNestedTokenTypePtr(tokenTypeCnt);//setting pointer of name and batting_avg
				bufDBServer::getDataTypeAndStore(tokenTypeCnt);//getting data from entry specified by entryCnt
				
				//Build column names and data values for each entry
				if(tokenTypeCnt == totalNestedTokenTypes-1)
				{
					//If it's the last entry don't put comma at the end
					colName<<getNestedTokenName();
				}					
				
				else
				{
					colName <<getNestedTokenName()<<",";
					values<<",";
				}
			}
			colName<<")";
			values<<")";
			
			addStringDataToTable();			
		}
	}
}


////////////////////////////////////////////////////////////////////////////////
// getDataTypeandStore()
//
// Description: This function will check to see what the type of the data is that 
//		is being pointed to by the current index and append the data of that type
//		to the string stream in the SaveToDatabase function which will create SQL
//		commands to add data to the database.
// Inputs: int tokenTypeCnt
// 
//
// Outputs: none
//
// Return: none
/////////////////////////////////////////////////////////////////////////////////
void bufDBServer::getDataTypeAndStore(int tokenTypeCnt)
{	
	//tempData.str("");
	if(getNestedTokenType()==FieldDescriptor::CPPTYPE_BOOL)
	{
		boolData=getNestedBool();
		values << boolData;
	}
	else if(getNestedTokenType()==FieldDescriptor::CPPTYPE_STRING)
	{
		stringData = getNestedString();	
		values << "'"+stringData+"'";
	}
	else if(getNestedTokenType()==FieldDescriptor::CPPTYPE_INT32)
	{
		int32Data = getNestedInt32();
		values << int32Data;
	}
	else if(getNestedTokenType()==FieldDescriptor::CPPTYPE_FLOAT)
	{
		floatData = getNestedFloat();
		values << floatData;
	}
	else if(getNestedTokenType()==FieldDescriptor::CPPTYPE_DOUBLE)
	{
		doubleData = getNestedDouble();
		values << doubleData;
	}
	else
	{
		cout<<"This nested type is not any of the allowable types."<<endl;
		cout<<"It is of type: "<<getNestedTokenType()<<endl;
	}
}


////////////////////////////////////////////////////////////////////////////////
// addStringDataToTable()
//
// Description: This function will execute the string stream SQL command
//		created in the SaveToDatabase function
// Inputs: none
// 
//
// Outputs: none
//
// Return: none
/////////////////////////////////////////////////////////////////////////////////
void bufDBServer::addStringDataToTable()
{   
    {        
        string dataEntry(
            "INSERT INTO " +  bufDBServer::getFieldName() + colName.str() +
			+ " VALUES " + values.str()+ ";");

         cout<<"STORING: "<<dataEntry<<endl;
         
         PGresult * result = PQexec(con, dataEntry.c_str());

        if (PQresultStatus(result) != PGRES_COMMAND_OK) {
            string duh(PQerrorMessage(con));
            string rstr("Command failed: " + duh);
            results += rstr;
            PQclear(result);
        }
    }
}


////////////////////////////////////////////////////////////////////////////////
// SaveToDatabase()
//
// Description: This function will query entire tables at a time, walk through the
//		query results and add the data to the protocol buffer to be sent back 
// 		to the client through the server-client socket
// Inputs: none
// 
//
// Outputs: none
//
// Return: none
/////////////////////////////////////////////////////////////////////////////////
void bufDBServer::RetrieveFromDatabase(void)
{
  
	msg = new db::Database();
	setNewMessage(msg);	
		
    //First Determine how many tables are in the database
    //Which is equivalent to the number of repeated fields in
    //the proto file.
    int totalProtoMsgs = findRepeatedFields();
	tableQuery="";
    
    for(int msgCnt = 0; msgCnt < totalProtoMsgs; msgCnt++)
    {
        //Set your indexes to point to the correct field
        //Repeated field gives you the data
        //Nested field gives you the type of data
        setRepeatedMsgPtr(msgCnt);
        setNestedTypePtr(msgCnt);

		//Create query for this table
		tableQuery = ("SELECT * FROM " + bufDBServer::getFieldName() + ";");
	
		//Retrieve pointer to entire table
		res = PQexec(con, tableQuery.c_str());
		if (PQresultStatus(res) != PGRES_TUPLES_OK) 
		{
		   fprintf(stderr, "Query failed: %s", PQerrorMessage(con));
		   PQclear(res);
		}	        

        //Once you are pointing at the correct Nested Type
        //you must determine the type of each token in the Nested Type
        //This is equivalent to the type of each comma seperated value
        //on a line of the input file.
        //int totalNestedTokenTypes = findNestedTokenTypes();		

        //Create a the first message element to set the entries in.
        //Each new line of the database needs to have an element
        //created in the proto buffer.
        //Thus subsequent elements will be created within the for loop.			
        for(int rowCnt = 0; rowCnt<PQntuples(res); rowCnt++)
        {
			cout<<"Number of rows: "<<PQntuples(res)<<endl;
			AddNestedMsgElement();			
           for(int columnCnt = 0; columnCnt<PQnfields(res); columnCnt++)
           {
				setNestedTokenTypePtr(columnCnt);
            
				string databaseString = PQgetvalue(res,rowCnt,columnCnt);
				cout<<"Received string from DB: "<<databaseString<<endl;
				setNestedSingleFieldFromString(databaseString);
			}
		}
	}
	cout<<"THIS IS THE STUFF FROM THE DATABASE!!"<<endl;
	msg->PrintDebugString();
}

